import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.geom.*;

public class ViewGraph extends JFrame implements ActionListener,MouseMotionListener
{
	double[][] coordinates;
	ArrayList<Point> points = new ArrayList<Point>();
	private Author[] authorsMap;
	private DBLPDatabase db;
	private double alpha = 1;
	private double beta = 1;
	private double wij = 1;
	
	Container pane ;
	private JButton exitButton;
	private JButton drawButton;
	private LayoutManager Layout;
	private JPanel panel;
	private JPanel drawPanel;
	private ZoomPanel zp;
	final static int maxGap = 20;
	//====================================================
	int numberOfAuthors =1; 
	int frameX = 1024;
	int frameY = 768;
	int scaleX = 1000;
	int scaleY = 1000;
	int regionX = 50;
	int regionY = 50;
	int mX = 0;
	int mY = 0;
	//====================================================
	public static void main(String[] args) throws SQLException
	{
		new ViewGraph();
	}
	public ViewGraph() throws SQLException
	{
		
		super("DrawCircle");
        setSize(frameX, frameY);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pane = getContentPane();
        
		
        exitButton = new JButton("Exit");
		exitButton.addActionListener(this);
		
		drawButton = new JButton("Draw");
		drawButton.addActionListener(this);
		
		
		panel = new JPanel();
		panel.setLayout(new BorderLayout(5,5));
		drawPanel = new JPanel();
		
		drawPanel.addMouseMotionListener(this);
		
		
		
		panel.add(BorderLayout.PAGE_END,exitButton);
		panel.add(BorderLayout.PAGE_START,drawButton);
		
		
		coordinates = new double[854332][3];
		loadCoordinates("MDS_2D_9.txt");
		db = new DBLPDatabase();
		 numberOfAuthors = db.getNumberOfAuthors();
		authorsMap = new Author[numberOfAuthors];
		initializeAuthorsMap();
		loadMap("map.txt");
		
		
		zp = new ZoomPanel();
		getContentPane().add(panel);
        setVisible(true);
	}
	public ViewGraph(double[][] coordinates)
	{
		/*super("DrawCircle");
        setSize(1024, 1024);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.coordinates = coordinates;
		pane = getContentPane();
		//DrawPoints dp = new DrawPoints();
       // pane.add(dp);
        setVisible(true);*/
	}
	public void updatePaint()
	{
		//DrawPoints dp = new DrawPoints();
       // pane.add(dp);
        //setVisible(true);
	}
	//================================================
	public void loadCoordinates(String fileName)
	{
		int count = 0;
		try
		{
			System.out.println("Loading coordinates ... ");
			File file = new File(fileName);
			FileReader fileReader = new FileReader(file);
			BufferedReader buffer = new BufferedReader(fileReader);
			//boolean link = true;
			while(true)
			{
				String line = buffer.readLine();
				if(line == null)break;
				String[] splitNodes = line.split(",");
			    coordinates[count][0] = Double.parseDouble(splitNodes[0].trim());
				coordinates[count][1] = Double.parseDouble(splitNodes[1].trim());
				count++;
				
			}
			;
			System.out.println(">Loading coordinates has been completed with ["+ count + "] authors");
		}
		catch(Exception ex)
		{
			System.out.println("Error 001:"+ex);
		}
	}
	//================================================
	class DrawPoints extends JPanel implements ActionListener,MouseMotionListener,MouseListener
	{
		Color color= Color.blue;
	    int radius = 2;
	    int mX = 0;
	    int mY = 0;
	    int pWidth =1024;
	    int pHight = 768;
		public DrawPoints()
		{
			super();
			this.addMouseMotionListener(this);
			this.addMouseListener( this);
			//setSize(pWidth, pHight);
			
		}
		public void paint(Graphics comp)
		{
			//System.out.println("paint called");
			Graphics2D comp2D = (Graphics2D)comp;
			comp2D.setColor(Color.white);
			comp2D.fillRect(0, 0, getSize().width, getSize().height);
			
			double sum = 0;
			double c1 = 0,c2=0,c3=0,c4=0,c5=0;
			for(int i=0;i<coordinates.length;i++)
			{
				double x = coordinates[i][0];
				double y = coordinates[i][1];
				double stress = getPointStress(i);
				if((x - regionX)<=scaleX && (y - regionY)<=scaleY)
				{
					double newX = (x * (getWidth()/(double)scaleX)) ;
					double newY = (y * (getHeight()/(double)scaleY)) ;
					int newR = radius * (getHeight()/scaleX);
					//if(newR<2) newR = 2;
					newR = 2;
					Ellipse2D.Double circle = new Ellipse2D.Double(newX,newY, newR, newR);
					
					sum = sum + stress;
				
					if(stress>0.65){comp2D.setPaint(Color.RED);c1++;}
					if(stress<=0.65 && stress>0.45){comp2D.setPaint(Color.ORANGE);c2++;}
					if(stress<=0.45 && stress>0.25){comp2D.setPaint(Color.YELLOW);c3++;}
					if(stress<=0.25 && stress>0.15){comp2D.setPaint(Color.GREEN);c4++;}
					if(stress<0.15){comp2D.setPaint(Color.BLACK);c5++;}
					comp2D.fill(circle);
					
					
				}
	      }
			System.out.println("Red: " + (c1/numberOfAuthors)*100.0);
			System.out.println("Orange: " + (c2/numberOfAuthors)*100.0);
			System.out.println("Yello: " + (c3/numberOfAuthors)*100.0);
			System.out.println("Green: " + (c4/numberOfAuthors)*100.0);
			System.out.println("Black: " + (c5/numberOfAuthors)*100.0);
			System.out.println("avg Stress = " + sum/854332);
			//System.out.println("paint has been completed");
		}
		//=====================================================
		public void paintComponent(Graphics comp) 
		{
		}
		@Override
		public void mouseDragged(MouseEvent e) 
		{
			//System.out.println("drag");
			//regionX = e.getX();
			//regionY = e.getY();
			//repaint();
			//panel.validate();
			
		}
		@Override
		public void mouseMoved(MouseEvent e) 
		{
			//setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
			mX = (int)e.getX();
			mY = (int)e.getY();
			//System.out.println(mX + "," + mY);
			ArrayList<double[]> coord = new ArrayList<double[]>();
			for(int i=0;i<coordinates.length;i++)
			{
				double x = coordinates[i][0];
				double y = coordinates[i][1];
				double newX = (x * (frameX/(double)scaleX));
				double newY = (y * (frameY/(double)scaleY));
				double stress = coordinates[i][2];
				if(newX>=mX && newX<=(mX + regionX) && newY>=mY && newY<=(mY+regionY))
				{
					double[] c = new double[]{newX - mX,newY - mY,stress,i};
					coord.add(c);
				}
			}
			zp.updateZoom(coord);
		}
		@Override
		public void actionPerformed(ActionEvent e) 
		{
			
		}
		public void mousePressed(MouseEvent e)
		{
			//System.out.println("pressed");
			//regionX = e.getX();
			//regionY = e.getY();
		}
		public void mouseReleased(MouseEvent e)
		{
			//System.out.println("released");
			
		}
		@Override
		public void mouseClicked(MouseEvent e) 
		{
			//setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
			mX = (int)e.getX();
			mY = (int)e.getY();
			//System.out.println(mX + "," + mY);
			ArrayList<double[]> coord = new ArrayList<double[]>();
			for(int i=0;i<coordinates.length;i++)
			{
				double x = coordinates[i][0];
				double y = coordinates[i][1];
				double newX = (x * (frameX/(double)scaleX));
				double newY = (y * (frameY/(double)scaleY));
				double stress = coordinates[i][2];
				if(newX>=mX && newX<=(mX + regionX) && newY>=mY && newY<=(mY+regionY))
				{
					double[] c = new double[]{newX - mX,newY - mY,stress,i};
					coord.add(c);
				}
			}
			zp.updateZoom(coord);
		}
		@Override
		public void mouseEntered(MouseEvent e) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void mouseExited(MouseEvent e) {
			// TODO Auto-generated method stub
			
		}
	}
	//==============================================================
	class ZoomPanel extends JFrame
	{
		JPanel zp;
		ArrayList<double[]> coord = new ArrayList<double[]>();
		public ZoomPanel()
		{
			super();
			zp = new JPanel();
			setSize(600, 400);
			Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
            this.setLocation((int)d.getWidth() - (int)this.getPreferredSize().getWidth(),
                    (int)d.getHeight() - (int)this.getPreferredSize().getHeight());
			getContentPane().add(zp);
			setVisible(true);
			
		}
		public void updateZoom(ArrayList<double[]> coord)
		{
			this.coord = coord;
			repaint();
		}
		public void paint(Graphics comp)
		{
			
			int radius = 2;
			Graphics2D comp2D = (Graphics2D)comp;
			comp2D.setColor(Color.white);
			comp2D.fillRect(0, 0, this.getSize().width, this.getSize().height);
			for(int i=0;i<coord.size();i++)
			{
				double x = coord.get(i)[0];
				double y = coord.get(i)[1];
				int id = (int) coord.get(i)[3];
				double stress = getPointStress(id);
				
				
				
				double newX = (x * (this.getSize().width/(double)regionX));
				double newY = (y  * (this.getSize().height/(double)regionY));
				int newR = radius * (this.getSize().height/regionX);
				//if(newR<2) newR = 2;
				newR = 6;
				Ellipse2D.Double circle = new Ellipse2D.Double(newX,newY, newR, newR);
				if(stress>0.65)comp2D.setPaint(Color.RED);
				if(stress<=0.65 && stress>0.45)comp2D.setPaint(Color.ORANGE);
				if(stress<=0.45 && stress>0.25)comp2D.setPaint(Color.YELLOW);
				if(stress<=0.25 && stress>0.15)comp2D.setPaint(Color.GREEN);
				if(stress<0.15)comp2D.setPaint(Color.BLACK);
				comp2D.fill(circle);
				
				
				//comp2D.drawString(Integer.toString(i+1), (float)newX, (float)newY);
				/*Integer[] coID = authorsMap[id].getCoauthorsID();
				for(int j=0;j<coID.length;j++)
				{
					//System.out.println("draw line");
					int cID = coID[j].intValue();
					double coX = coordinates[cID-1][0];
					double coY = coordinates[cID-1][1];
					double newcoX = (coX * (this.getSize().width/(double)regionX));
					double newcoY = (coY  * (this.getSize().height/(double)regionY));
					Line2D line = new Line2D.Double(newX,newY,newcoX,newcoY);
					comp2D.setPaint(Color.BLUE);
					comp2D.setStroke(new BasicStroke(1));
					comp2D.draw(line);
				}*/
			}
			
		}
	}
	//==============================================================
	void paintComponent(Graphics g)
	{
		System.out.println("paint comp called");
	}
	//=================================================
	@Override
	public void actionPerformed(ActionEvent e) 
	{
		if(e.getSource() == drawButton)
		{
			System.out.println("Drawing ....");
			DrawPoints dp = new DrawPoints();
			
			panel.add(BorderLayout.CENTER,dp);
			panel.validate();
			System.out.println("Drawing .... completed");
			//getContentPane().add(dp);
			
		}
		if(e.getSource() == exitButton)
		{
			System.exit(0);
		}
	}
	//=========== load map ===========================
	public void loadMap(String fileName)
	{
		int count = 0;
		System.out.println(">Loading the map structure ... ");
		try
		{
			File file = new File(fileName);
			FileReader fileReader = new FileReader(file);
			BufferedReader buffer = new BufferedReader(fileReader);
			//boolean link = true;
			while(true)
			{
				String line = buffer.readLine();
				if(line == null)break;
				String[] splitNodes = line.split("-");
				int aID = Integer.parseInt(splitNodes[0].split(",")[0]);
				Author author = new Author(aID);
				//System.out.println(splitNodes[0]);
				for(int i=1;i<splitNodes.length;i++)
				{
					int coID = Integer.parseInt(splitNodes[i].split(",")[0]);
					double weight = Double.parseDouble(splitNodes[i].split(",")[1]);
					author.addCoAuthor(coID,(int)weight);
				}
				authorsMap[aID-1] = author;
				count++;
			}
			//System.out.println(count);
			System.out.println(">Loading the map structure has been completed with ["+ count + "] authors");
		
		}
		catch(Exception ex)
		{
			System.out.println("Error 001:"+ex.getMessage());
		}
		 
	}
	//================================================
	public void initializeAuthorsMap()
	{
		for(int i=0;i<authorsMap.length;i++)
		{
			Author author = new Author(i+1);
			authorsMap[i] = author;
		}
	}
	//================================================
	public double getPointStress(int pointID)
	{
		double diff_sum_2 =0;
		double pXi1 = 0;
		double pXi2 = 0;
		int aid1 = authorsMap[pointID].authorID;
		Integer[] listOfCoauthorsID = authorsMap[pointID].getCoauthorsID();
		for(int j=0;j<listOfCoauthorsID.length;j++)
		{
			
			int aid2 = listOfCoauthorsID[j];
			if(aid1!=aid2)
			{
				// sum [wij(fij - dij)^2]
				diff_sum_2 = diff_sum_2 + wij * Math.pow((getDisparities(aid1,aid2) - getDistance (aid1, aid2)),2);
				// sum[( fij - dij(x)) . dij(x)^-1 . (Xi1 - Xj1)
				//double t1 = getDisparities(aid1,aid2) - getDistance (aid1, aid2);
				//double t2 = 1/getDistance (aid1, aid2);
				//double t31 = coordinates[aid1-1][0] - coordinates[aid2-1][0];
				//double t32 = coordinates[aid1-1][1] - coordinates[aid2-1][1];
			
			
				//pXi1 = pXi1 + t1*t2*t31;
				//pXi2 = pXi2 + t1*t2*t32;
				
				//sum_pStress = sum_pStress + getDistance(aid1,aid2);
			}
		}
		return diff_sum_2;
	}
	//==================================================
	public double getDisparities(int aID1,int aID2)
	{
		double f = 0.0;
		int weight = authorsMap[aID1-1].getWeight(aID2);
		if(weight>0)
		{
			f = alpha * Math.pow(weight, -1*beta);
		}
		return f;
	}
	//================================================
	public double getDistance(int aid1,int aid2)
	{
		double d = 0.0;
		// calc dij(x) = sqrt((xi2 - xj1)^2 + (xi2 - xj2)^2)
		double c1 = (coordinates[aid2-1][0] - coordinates[aid1-1][0]);
		double c2 = (coordinates[aid2-1][1] - coordinates[aid1-1][1]);
		double sum = Math.pow(c1,2) + Math.pow(c2,2);
		d = Math.sqrt(sum);
		return d;
	}
	//=========== events =============================
	@Override
	public void mouseDragged(MouseEvent arg0) 
	{
		System.out.println("mouse dragged");
	}
	@Override
	public void mouseMoved(MouseEvent mouse) 
	{
		mX = (int)mouse.getX();
		mY = (int)mouse.getY();
		//repaint();
		
	}
}

